package com.youlu.campus.service.order.impl;

import com.alibaba.fastjson.JSON;

import com.youlu.campus.entity.OrderInfo;
import com.youlu.campus.entity.VO.req.OrderPriceStatisticsQueryVO;
import com.youlu.campus.entity.data.OrderPriceStatistics;
import com.youlu.campus.service.order.OrderPriceStatisticsService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Sort;
import org.springframework.data.mongodb.core.MongoTemplate;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.data.mongodb.core.query.Update;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.repository.support.PageableExecutionUtils;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.util.*;

@Slf4j
@Service
public class OrderPriceStatisticsServiceImpl implements OrderPriceStatisticsService {
    @Autowired
    private MongoTemplate mongoTemplate;
    @Autowired
    private StringRedisTemplate stringRedisTemplate;

    private String ORDER_PRICE_STATISTICS = "com.luyou.order-price-statistics:::";
    // 订单总数量
    private String ORDER_PRICE_STATISTICS_TOTAL = "..total";
    private String ORDER_PRICE_STATISTICS_GMV = "..gmv";
    private String ORDER_PRICE_STATISTICS_REFUND_GMV = "..refund-gmv";
    private String ORDER_PRICE_STATISTICS_REFUND_NUM = "..refund-num";
    private String ORDER_PRICE_STATISTICS_DETAIL = "..pay-num:%d";
    public static HashMap<String, Long> mobileMap = new HashMap<>();

    @Override
    public Page<OrderPriceStatistics> list(OrderPriceStatisticsQueryVO req) {
        Query query = new Query();
        Long count = mongoTemplate.count(query, OrderPriceStatistics.class);
        log.info(":>>> 订单价格分析的数量:{}，查询条件:{}", count, JSON.toJSON(query));
        PageRequest pageRequest = PageRequest.of(req.getPage() - 1, req.getPageSize());
//        query.with(new Sort(Sort.Direction.DESC, "num"));
        Sort sort=Sort.by(Sort.Direction.DESC, "num");
        query.with(sort);
        List<OrderPriceStatistics> orderPOS = mongoTemplate.find(query.with(pageRequest), OrderPriceStatistics.class);
        String totalO = stringRedisTemplate.opsForValue().get(ORDER_PRICE_STATISTICS + ORDER_PRICE_STATISTICS_TOTAL);
        String gmvO = stringRedisTemplate.opsForValue().get(ORDER_PRICE_STATISTICS + ORDER_PRICE_STATISTICS_GMV);
        log.info(":>>> 订单总数量:{},GMV:{}", totalO, gmvO);
        Double total = 0.0D;
        Double gmv = 0.0D;
        if (Objects.nonNull(totalO)) {
            total = Double.valueOf(totalO);
        }
        if (Objects.nonNull(gmvO)) {
            gmv = Double.valueOf(gmvO);
        }
        for (OrderPriceStatistics orderPriceStatistics : orderPOS) {
            if (total.compareTo(0.0D) != 0) {
                orderPriceStatistics.setPayNumRatio(fun1(orderPriceStatistics.getNum() * 100 / total));
            }
            if (gmv.compareTo(0.0D) != 0) {
                orderPriceStatistics.setPayGmvRatio(fun1(orderPriceStatistics.getGmv() * 100 / gmv));
            }
        }
        return PageableExecutionUtils.getPage(orderPOS, pageRequest, () -> count);
    }

    @Override
    public OrderPriceStatistics findByPayNum(Integer num) {
        Query query = new Query().addCriteria(Criteria.where("payNum").is(num));
        OrderPriceStatistics o = mongoTemplate.findOne(query, OrderPriceStatistics.class);
        return o;
    }

    @Async
    @Override
    public void update(OrderPriceStatistics req) {
        if (Objects.isNull(req) || StringUtils.isBlank(req.getId())) {
            log.error(":>>> 修改参数错误");
            return;
        }
        Query query = new Query().addCriteria(Criteria.where("id").is(req.getId()));
        Update update = new Update();
        if (Objects.nonNull(req.getNum())) {
            update.inc("num", req.getNum());
        }
        if (Objects.nonNull(req.getGmv())) {
            update.inc("gmv", req.getGmv());
        }
        if (Objects.nonNull(req.getRefundGmv())) {
            update.inc("refundGmv", req.getRefundGmv());
        }
        if (Objects.nonNull(req.getRefundNum())) {
            update.inc("refundNum", req.getRefundNum());
        }
        update.set("updatedTime", new Date());
        mongoTemplate.updateFirst(query, update, OrderPriceStatistics.class);
    }

    @Override
    public void create(OrderPriceStatistics req) {
        req.setId(null);
        req.setCreatedTime(new Date());
        mongoTemplate.insert(req);
    }

    //    @Async
    @Override
    public void increOrderInfo(OrderInfo orderInfo, Long count) {
        try {
            if (Objects.isNull(orderInfo) || StringUtils.isBlank(orderInfo.getMobile()) ||
                    StringUtils.isBlank(orderInfo.getStatus()) || "0".equals(orderInfo.getStatus())) {
                log.error(":>>> 累加订单参数错误:手机号、订单编号、或状态错误");
                return;
            }
            log.info(":>>> 开始更新订单:{}", orderInfo.getOrderNo());
            if (Objects.isNull(count)) {
                Query query = new Query().addCriteria(Criteria.where("mobile").is(orderInfo.getMobile()).and("status").ne("0"));
                count = mongoTemplate.count(query, OrderInfo.class);
                mobileMap.put(orderInfo.getMobile(), count);
                log.info(":>>> 手机号:{}, 购买次数:{}", orderInfo.getMobile(), count);
            }
            Integer c = count.intValue();
            OrderPriceStatistics orderPriceStatistics = this.findByPayNum(c);
            boolean created = false;
            if (Objects.isNull(orderPriceStatistics)) {
                log.info(":>>> 购买次数:{} 不存在", count);
                orderPriceStatistics = new OrderPriceStatistics();
                orderPriceStatistics.setPayNum(c);
                orderPriceStatistics.setNum(1.0D);
                created = true;
            } else {
                orderPriceStatistics.setNum(1.0D);
            }

            orderPriceStatistics.setGmv(Double.valueOf(orderInfo.getTotalFee() / 100));
            if ("1".equals(orderInfo.getVerifyStatus()) || "2".equals(orderInfo.getVerifyStatus())) {
                orderPriceStatistics.setRefundGmv(Double.valueOf(orderInfo.getTotalFee() / 100));
                orderPriceStatistics.setRefundNum(1);
                stringRedisTemplate.opsForValue().increment(ORDER_PRICE_STATISTICS + ORDER_PRICE_STATISTICS_REFUND_GMV, Double.valueOf("" + orderInfo.getTotalFee() / 100));
                stringRedisTemplate.opsForValue().increment(ORDER_PRICE_STATISTICS + ORDER_PRICE_STATISTICS_REFUND_NUM, 1L);
            }
            stringRedisTemplate.opsForValue().increment(ORDER_PRICE_STATISTICS + ORDER_PRICE_STATISTICS_TOTAL, 1L);
            stringRedisTemplate.opsForValue().increment(ORDER_PRICE_STATISTICS + ORDER_PRICE_STATISTICS_GMV, Double.valueOf("" + orderInfo.getTotalFee() / 100));
            stringRedisTemplate.opsForValue().increment(ORDER_PRICE_STATISTICS + String.format(ORDER_PRICE_STATISTICS_DETAIL, c), 1L);
            if (created) {
                this.create(orderPriceStatistics);
                return;
            }
            this.update(orderPriceStatistics);
        } catch (Exception e) {
            log.error(":>>>  更新订单统计错误:{}", e);

        }
    }

    @Override
    public void all(OrderPriceStatisticsQueryVO req) {
        List<String> mobiles = new ArrayList<>();
        Query query = new Query().addCriteria(Criteria.where("status").ne("0"));
        if (Objects.nonNull(req)) {
            Criteria criteriaPay = null;
            if (req.getStartTime() != null || req.getEndTime() != null) {
                criteriaPay = Criteria.where("payTime");
                if (req.getStartTime() != null) {
                    criteriaPay.gte(req.getStartTime());
                }
                if (req.getEndTime() != null) {
                    criteriaPay.lte(req.getEndTime());
                }
            }
            if (Objects.nonNull(criteriaPay)) {
                query.addCriteria(criteriaPay);
            }
        }
        Long count = mongoTemplate.count(query, OrderInfo.class);
        log.info(":>>> 订单总数量:[}", count);
        Integer pageSize = 10000;
        Integer pages = count.intValue() / pageSize + 1;
        for (Integer page = 0; page < pages; page++) {
            log.info(":>>> 开始处理第:{} 页", page);
            query.skip(page * pageSize);
            query.limit(pageSize);
            List<OrderInfo> orderInfos = mongoTemplate.find(query, OrderInfo.class);
            if (Objects.isNull(orderInfos)) {
                return;
            }
            for (OrderInfo orderInfo : orderInfos) {
                if (mobileMap.containsKey(orderInfo.getMobile())) {
                    log.info(":>>> 手机号:{} 在数量中", orderInfo.getMobile());
                    this.increOrderInfo(orderInfo, mobileMap.get(orderInfo.getMobile()));
                } else {
                    log.info(":>>> 手机号:{}  不在在数量中", orderInfo.getMobile());
                    this.increOrderInfo(orderInfo, null);
                }
                mobiles.add(orderInfo.getMobile());
            }
        }

    }

    public double fun1(double f) {
        BigDecimal bg = new BigDecimal(f);
        /**
         * 参数：
         newScale - 要返回的 BigDecimal 值的标度。
         roundingMode - 要应用的舍入模式。
         返回：
         一个 BigDecimal，其标度为指定值，其非标度值可以通过此 BigDecimal 的非标度值乘以或除以十的适当次幂来确定。
         */
        double f1 = bg.setScale(2, BigDecimal.ROUND_HALF_UP).doubleValue();
        return f1;
    }
}
